package com.mrogrape.notepad.common;

import info.monitorenter.cpdetector.io.ASCIIDetector;
import info.monitorenter.cpdetector.io.CodepageDetectorProxy;
import info.monitorenter.cpdetector.io.JChardetFacade;
import info.monitorenter.cpdetector.io.ParsingDetector;
import info.monitorenter.cpdetector.io.UnicodeDetector;

import java.awt.Desktop;
import java.awt.Desktop.Action;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.List;

import com.mrogrape.notepad.activity.MainFrame;
import com.mrogrape.notepad.data.ViewContext;
import com.mrogrape.notepad.ui.editor.TextEditor;
import com.mrogrape.util.StringUtils;


public class NotepadUtils {

	/**
	 * 探测一个文本文件的文本编码,默认读取6144字节长度的文件用于测试。
	 * @param in
	 * @return
	 * @throws IllegalArgumentException
	 * @throws IOException
	 */
	public static final String sniffCharset(InputStream in) throws IllegalArgumentException, IOException{

		return NotepadUtils.sniffCharset(in, 6144);
	}

	/**
	 * 探测一个文本文件的文本编码。
	 * 
	 * @param file 需要探测的文件
	 * @param test 用于探测的字节数，越大越准确，但越消耗时间。
	 * @return 探测到的文本编码
	 * @throws IllegalArgumentException 
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	public static final String sniffCharset(File file) throws IllegalArgumentException, FileNotFoundException, IOException{

		if(NotepadUtils.charsetSniffer == null){
			NotepadUtils.initCharsetSniffer();
		}

		Charset charset = NotepadUtils.charsetSniffer.detectCodepage(file.toURI().toURL());

		if(charset != null){
			return charset.name();
		}
		else{
			return null;
		}

	}

	/**
	 * 探测一个文本文件的文本编码。
	 * @param in
	 * @param test
	 * @return
	 * @throws IllegalArgumentException
	 * @throws IOException
	 */
	public static final String sniffCharset(InputStream in, int test) throws IllegalArgumentException, IOException{

		if(NotepadUtils.charsetSniffer == null){
			NotepadUtils.initCharsetSniffer();
		}

		Charset charset = NotepadUtils.charsetSniffer.detectCodepage(in, test);

		if(charset != null){
			return charset.name();
		}
		else{
			return null;
		}
	}

	/**
	 * 初始化编码嗅探器
	 */
	private static void initCharsetSniffer(){
		NotepadUtils.charsetSniffer = CodepageDetectorProxy.getInstance();
		NotepadUtils.charsetSniffer.add(new ParsingDetector(true));
		NotepadUtils.charsetSniffer.add(JChardetFacade.getInstance());
		NotepadUtils.charsetSniffer.add(ASCIIDetector.getInstance());
		NotepadUtils.charsetSniffer.add(UnicodeDetector.getInstance());
	}

	/** 编码嗅探器 */
	private static CodepageDetectorProxy charsetSniffer = null;

	/**
	 * 获取与参照文件/文件夹最近的文件。
	 * 
	 * @param ref
	 * @param name
	 * @return
	 */
	public static File createNearlyFilePath(File ref, String name){

		// 参数检查
		if(StringUtils.isEmpty(name)){

			throw new IllegalArgumentException("Name cannot be empty.");
		}

		// 获取父文件夹
		String dir = System.getProperty("user.home");
		if(ref != null){

			// 如果参照文件是一个文件夹。
			if(ref.isDirectory()){
				dir = ref.getAbsolutePath();
			}
			else{
				dir = ref.getParent();
			}
		}

		return new File(new File(dir), name);
	}

	/**
	 * 在系统浏览器中浏览指定的URL。
	 * 
	 * @param url
	 * @throws IOException
	 * @throws URISyntaxException
	 */
	public static void browseURL(URL url) throws IOException, URISyntaxException{

		Desktop.getDesktop().browse(url.toURI());
	}

	/**
	 * 打开文件所在位置。
	 * 
	 * @param file 文件，或文件夹
	 * @throws IOException 如果在打开的过程中发生IOException
	 */
	public static void openFileLocation(File file) throws IOException{

		if(!Desktop.isDesktopSupported()||!Desktop.getDesktop().isSupported(Action.OPEN)){
			return;
		}
		File dir = null;
		if(file == null){

			dir = new File(System.getProperty("user.home"));
		}
		else if(file.isFile()){

			dir = file.getParentFile();
		}
		else{

			dir = file;
		}

		Desktop.getDesktop().open(dir);
	}

	/**
	 * 通过系统关联打开一个文件。
	 * 
	 * @param file
	 * @throws IOException
	 */
	public static void openFileInSystem(File file) throws IOException{

		if(Desktop.isDesktopSupported()&&Desktop.getDesktop().isSupported(Action.OPEN)){
			Desktop.getDesktop().open(file);
		}
	}

	/**
	 * 获取文件的扩展名。
	 * 
	 * @param file
	 * @return
	 */
	public static String getFileExtension(File file){

		if (file == null) { return null; }

		String name = file.getName();

		int index = name.lastIndexOf(".");
		if(index > 0 && (index < name.length() - 1)){
			return name.substring(index + 1);
		}

		return null;
	}

	/**
	 * 查看一个文件是否已经在文本编辑器中被打开。
	 * 
	 * @param file
	 * @return
	 */
	public static boolean isFileOpened(File file){

		return NotepadUtils.findFileEditor(file)!=null;

	}

	/**
	 * 查找某个文件的编辑器，如果文件尚未打开，则返回null;
	 * 
	 * @param file 需要查找的文件
	 * @return 如果该文件已经被某个编辑器打开则返回该编辑器，否则返回null。
	 */
	private static TextEditor findFileEditor(File file){

		if(file == null){
			return null;
		}

		TextEditor rEditor = null;
		MainFrame frame = ViewContext.getMainFrame();

		List<TextEditor> editors = frame.getAllTextEditors();
		for(TextEditor editor:editors){
			if(file.equals(editor.getFile())){
				return editor;
			}
		}

		return rEditor;
	}

}
